package com.ext.aic.box.wx.conversation;

import android.content.Context;
import android.text.TextUtils;

import com.ext.aic.AICApplication;
import com.ext.aic.AICManager;
import com.ext.aic.beans.OCRProcessMeta;
import com.ext.aic.beans.box.NotificationMessage;
import com.ext.aic.beans.ocr.BoundingBox;
import com.ext.aic.beans.ocr.ConversationAnalyzeResult;
import com.ext.aic.beans.ocr.OcrBody;
import com.ext.aic.beans.ocr.OcrText;
import com.ext.aic.events.OnAccessibilityServiceEvent;
import com.ext.aic.events.OnRecognizeListener;
import com.ext.aic.handler.OCRPoolHandler;
import com.ext.aic.utils.BoxUtils;
import com.eyinfo.android_pure_utils.events.Action1;
import com.eyinfo.android_pure_utils.utils.JsonUtils;
import com.eyinfo.android_pure_utils.utils.ObjectJudge;
import com.eyinfo.android_pure_utils.utils.PixelUtils;
import com.eyinfo.android_pure_utils.utils.ValidUtils;
import com.eyinfo.storage.files.FileUtils;

import java.io.File;
import java.util.Deque;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.CountDownLatch;
import java.util.regex.Pattern;

import lombok.Getter;

public class ConversationRecognize {

    private Deque<File> deque = new ConcurrentLinkedDeque<>();
    private boolean detecting;
    @Getter
    private boolean recognizing = false;

    private void recognize(File file) {
        OCRPoolHandler ocrPoolHandler = new OCRPoolHandler();
        ocrPoolHandler.setRecognitionListener(new OnRecognizeListener() {
            @Override
            public void onRecognizeCall(String result, int position, String fileId, String extension) {
                if (!ObjectJudge.isJson(result)) {
                    detecting = false;
                    return;
                }
                analyze(result, fileId, extension, false);
                detecting = false;
                detection();
            }
        });
        OCRProcessMeta meta = new OCRProcessMeta();
        meta.setPath(file.getAbsolutePath());
        ocrPoolHandler.process(meta, 0);
    }

    public void startRecognizeDetection() {
        if (recognizing) {
            return;
        }
        recognizing = true;
        if (!detecting) {
            roundScreenshot();
        }
        detection();
    }

    private void detection() {
        if (deque.isEmpty()) {
            detecting = false;
            recognizing = false;
            //step7 分页结束后触发回复任务(实际触发条件已在方法内部判断)
            OnAccessibilityServiceEvent serviceEvent = BoxUtils.getInstance().getServiceEvent();
            serviceEvent.triggerReplyTask(null);
            return;
        }
        if (detecting) {
            return;
        }
        detecting = true;
        File file = deque.poll();
        if (file == null) {
            detecting = false;
            detection();
            return;
        }
        recognize(file);
    }

    private void roundScreenshot() {
        File dir = BoxUtils.getInstance().getAccessibilityScreenshotDir();
        File[] files = dir.listFiles();
        if (ObjectJudge.isNullOrEmpty(files)) {
            return;
        }
        for (File file : files) {
            if (!file.isFile() || !hasTargetSuffix(file)) {
                file.deleteOnExit();
                continue;
            }
            deque.add(file);
        }
    }

    private boolean hasTargetSuffix(File file) {
        String absolutePath = file.getAbsolutePath();
        String extension = FileUtils.getExtension(absolutePath);
        return extension.endsWith("jpg") || extension.endsWith("jpeg") || extension.endsWith("png");
    }

    private String filterInvalidText(String text) {
        String mText = text.trim();
        if (mText.startsWith("|")) {
            if (mText.length() == 1) {
                return "";
            }
            mText = mText.substring(1);
        }
        if (mText.endsWith(" C")) {
            if (mText.length() == 2) {
                return "";
            }
            mText = mText.substring(0, mText.length() - 2);
        }
        mText = mText.replaceAll("伎", "传");
        mText = mText.replaceAll("往", "住");
        mText = mText.replaceAll("爸首", "爸爸");
        return mText;
    }

    private void removeInvalidText(List<OcrText> texts) {
        Context applicationContext = AICApplication.getInstance().getApplicationContext();
        Set<OcrText> removeItems = new HashSet<>();
        for (int i = 0; i < texts.size(); i++) {
            OcrText ocrText = texts.get(i);
            if (ocrText == null || TextUtils.isEmpty(ocrText.getText()) || ocrText.getBoundingBox() == null) {
                removeItems.add(ocrText);
                continue;
            }
            //过滤角标数字
            BoundingBox boundingBox = ocrText.getBoundingBox();
            int height = Math.abs(boundingBox.getBottom() - boundingBox.getTop());
            int width = Math.abs(boundingBox.getRight() - boundingBox.getLeft());
            int maxWidth = PixelUtils.dip2px(applicationContext, 27);
            int maxHeight = PixelUtils.dip2px(applicationContext, 15);
            if (width <= maxWidth &&
                    height <= maxHeight &&
                    Pattern.matches("^(?:\\d+|99\\+|\\.{3}|99)$", ocrText.getText()) &&
                    !isLeftAlignment(texts, ocrText)) {
                removeItems.add(ocrText);
                continue;
            }
            //过滤前后无效文本
            String filtered = filterInvalidText(ocrText.getText());
            if (TextUtils.isEmpty(filtered)) {
                removeItems.add(ocrText);
                continue;
            }
            ocrText.setText(filtered);
        }
        if (!ObjectJudge.isNullOrEmpty(removeItems)) {
            texts.removeAll(removeItems);
        }
    }

    private boolean isLeftAlignment(List<OcrText> texts, OcrText ocrText) {
        BoundingBox boundingBox = ocrText.getBoundingBox();
        int left = boundingBox.getLeft();
        for (OcrText text : texts) {
            BoundingBox box = text.getBoundingBox();
            int boxLeft = box.getLeft();
            int offset = Math.abs(left - boxLeft);
            if (offset <= 2) {
                return true;
            }
        }
        return false;
    }

    private String getMessageTime(List<OcrText> texts) {
        String time = "";
        int pos = -1;
        for (int i = 0; i < texts.size(); i++) {
            String text = texts.get(i).getText();
            time = ValidUtils.matche("(?:[01]\\d|2[0-3]|0?[1-9]|1[0-2]):[0-5]\\d", text);
            if (!TextUtils.isEmpty(time)) {
                pos = i;
                break;
            }
        }
        if (pos >= 0) {
            texts.remove(pos);
        }
        return time;
    }

    private ConversationAnalyzeResult getAnalyzeResult(OcrBody body) {
        ConversationAnalyzeResult result = new ConversationAnalyzeResult();
        List<OcrText> texts = body.getTexts();
        //数据为空或只识别到一个数据均为无效
        //过滤掉角标数字
        removeInvalidText(texts);
        if (ObjectJudge.isNullOrEmpty(texts) || texts.size() < 2) {
            result.setInvalid(true);
            return result;
        }
        String first = Objects.toString(texts.remove(0).getText(), "");
        String[] firstSplit = first.split("\\n");
        if (firstSplit.length > 1) {
            result.setUser(firstSplit[0]);
            result.setMessage(firstSplit[1]);
            result.setTime(getMessageTime(texts));
        } else {
            result.setUser(first);
            result.setTime(getMessageTime(texts));
            result.setMessage(texts.get(0).getText());
        }
        result.setInvalid(false);
        return result;
    }

    private NotificationMessage analyze(String json, String fileId, String extension, boolean isSync) {
        try {
            OcrBody body = JsonUtils.parseT(json, OcrBody.class);
            ConversationAnalyzeResult analyzeResult = getAnalyzeResult(body);
            if (analyzeResult.isInvalid()) {
                return null;
            }
            NotificationMessage notifyMessage = BoxUtils.getInstance().getNotifyMessage(analyzeResult.getUser(), analyzeResult.getMessage());
            if (!isSync) {
                AICManager.getInstance().insertOrUpdate(NotificationMessage.class, notifyMessage);
            }
            return notifyMessage;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    static class SynchronizeRecognizeParam {
        public NotificationMessage notificationMessage;
        public CountDownLatch latch;
        public File file;
    }

    private void startRecognizeWithSingle(File file, Action1<NotificationMessage> callback) {
        OCRPoolHandler ocrPoolHandler = new OCRPoolHandler();
        ocrPoolHandler.setRecognitionListener(new OnRecognizeListener() {
            @Override
            public void onRecognizeCall(String result, int position, String fileId, String extension) {
                if (TextUtils.equals(result, "finish")) {
                    NotificationMessage message = new NotificationMessage();
                    message.setFinish(1);
                    callback.call(message);
                } else {
                    if (!ObjectJudge.isJson(result)) {
                        callback.call(null);
                        return;
                    }
                    NotificationMessage notificationMessage = analyze(result, fileId, extension, true);
                    callback.call(notificationMessage);
                }
            }
        });
        OCRProcessMeta meta = new OCRProcessMeta();
        meta.setPath(file.getAbsolutePath());
        ocrPoolHandler.process(meta, 0);
    }

    public void singleRecognize(Long screenshotId, Action1<NotificationMessage> callback) {
        try {
            File dir = BoxUtils.getInstance().getAccessibilityScreenshotDir();
            String fileName = String.format("%s.jpg", screenshotId);
            File file = new File(dir, fileName);
            if (!file.exists()) {
                callback.call(null);
                return;
            }
            startRecognizeWithSingle(file, callback);
        } catch (Exception e) {
            e.printStackTrace();
            callback.call(null);
        }
    }
}
